package org.ucas.kgraph.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.ucas.kgraph.dto.*;
import org.ucas.kgraph.entity.Document;
import org.ucas.kgraph.entity.Relation;
import org.ucas.kgraph.entity.RelationType;
import org.ucas.kgraph.entity.Schem;
import org.ucas.kgraph.entity.Term;
import org.ucas.kgraph.service.DocumentService;
import org.ucas.kgraph.service.RelationService;
import org.ucas.kgraph.service.SchemService;
import org.ucas.kgraph.service.TermService;
import org.ucas.kgraph.utils.exception.BadRequestException;
import org.ucas.kgraph.utils.exception.ConflictException;
import org.ucas.kgraph.utils.exception.NotFoundException;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Function;

import javax.servlet.http.HttpServletRequest;

import java.io.IOException;
import java.util.List;

@RestController
public class TermController extends BaseController {

  @Autowired
  private TermService termService;
  
  @Autowired
  private SchemService schemService;
  
  @Autowired
  private DocumentService documentService;

  @Autowired
  private RelationService relationService;


  @RequestMapping(value = "/terms",method = RequestMethod.POST)
  public CarryDto<TermDto> create( HttpServletRequest request){
    Long parentId = request.getParameter("parent")==null?null:Long.valueOf(request.getParameter("parent"));
    TermDto dto = TermDto.from(request);
    Term tmp = new Term();
    dto.writeTo(tmp);
    if(tmp.getRootId()==null) tmp.setRootId(root());
    if(tmp.getRootId()==null) tmp.setRootId(Long.valueOf(-1));

    tmp.setFile_id(file());
    if(parentId==null) termService.create(tmp);
    else termService.createWithParent(tmp,parentId);
    dto.id = tmp.getId();
    return CarryDto.of(dto);
  }

  @RequestMapping(value = "/terms/{id:\\d+}",method = RequestMethod.DELETE)
  public ResponseDto delete(@PathVariable Long id){
    termService.delete(id);
    return ResponseDto.OK;
  }
  
  @RequestMapping(value = "/terms/{id:\\d+}/delete",method = RequestMethod.DELETE)
  public ResponseDto deleteAll(@PathVariable Long id){
	  termService.deleteAll(id, root());
	  return ResponseDto.OK;
  }
  @RequestMapping(value = "/terms/{id:\\d+}/deleteroot",method = RequestMethod.DELETE)
  public ResponseDto deleteRoot(@PathVariable Long id){
	  termService.deleteAll(id, id);
	  return ResponseDto.OK;
  }
  @RequestMapping(value = "/terms/{id:\\d+}/deleteDocument",method = RequestMethod.DELETE)
  public ResponseDto deletedocument(@PathVariable Long id) throws JsonParseException, JsonMappingException, IOException {
	
	Term term = termService.load(id);
	term.setCost(Float.valueOf(0));
	term.setDocumentId(null);
    termService.save(term);
	return ResponseDto.OK;
  }
  @RequestMapping(value = "/terms/{id:\\d+}/deleteTags",method = RequestMethod.DELETE)
  public ResponseDto deletetags(@PathVariable Long id) throws JsonParseException, JsonMappingException, IOException {
	Term term = termService.load(id);
	term.setTags(null);
    termService.save(term);
	return ResponseDto.OK;
  }
  @RequestMapping(value = "/terms/{id:\\d+}/cut",method = RequestMethod.DELETE)
  public ResponseDto cutThis(@PathVariable Long id){
	  Term tmp=termService.parent(id, root());
	  List <Term> ltmp= termService.listChildren(id, root());
	  for(int i=0;i<ltmp.size();i++){
		  relationService.reparent(ltmp.get(i).getId(),id,tmp.getId());
	  }
	  termService.delete(id);
	  return ResponseDto.OK;
  }

  @RequestMapping(value = "/terms/{id:\\d+}/submitm",method = RequestMethod.PUT)
  public CarryDto<SchemDto> submitm(@PathVariable Long id,@RequestParam("file_id") Long file_id) throws JsonParseException, JsonMappingException, IOException {
	
	Schem schem = schemService.load(id);
	
    termService.saveGraph(schem.getContent(),file_id);
    
    schemService.delete(id);
	return CarryDto.of(schem);
  }
  @RequestMapping(value = "/terms/{id:\\d+}/refile",method = RequestMethod.PUT)
  public ResponseDto refile(@PathVariable Long id,@RequestParam("file_id") Long file_id){
    if(file_id.equals(file())) throw NotFoundException.Term_NotExists;
	termService.refile(id,file_id);
 	return ResponseDto.OK;
  }
  @RequestMapping(value = "/terms/{id:\\d+}/retags",method = RequestMethod.PUT)
  public CarryDto<TermDto> update(@RequestBody TermDto dto,@PathVariable Long id){
    Term dst = termService.load(id);
    if (dst == null) throw NotFoundException.Term_NotExists;
    dto.writeTo(dst);
    termService.save(dst);
    return CarryDto.of(dto);
  }

  @RequestMapping(value = "/terms/{id:\\d+}",method = RequestMethod.GET)
  public CarryDto<TermDto> load(@PathVariable Long id){
    Term term = termService.load(id);
    if(term == null) throw NotFoundException.Term_NotExists;
    else return CarryDto.of(TermDto.of(term));
  }

  /**
   * @return 所有的顶级主题
   */
  @RequestMapping(value = "/terms/roots",method = RequestMethod.GET)
  public ListDto<TermDto> roots(){
    return ListDto.of(termService.listRoots(file()),TermDto::of);
  }
  /**
   * 设定默认顶级主题
   * @param rootId
   * @return
   */
  
  @RequestMapping(value = "/terms/roots/select",method = RequestMethod.GET)
  public ResponseDto selectRoot(@RequestParam("root") Long rootId){
    root(rootId);
    return ResponseDto.OK;
  }
  
  @RequestMapping(value = "/terms/roots/search",method = RequestMethod.GET)
  public ResponseDto selectSearchRoot(@RequestParam("searchroot") Long rootId){
    searchroot(rootId);
    return ResponseDto.OK;
  }
  
  @RequestMapping(value = "/terms/{id:\\d+}/rename",method = RequestMethod.PUT)
  public CarryDto<TermDto> rename(@PathVariable Long id,@RequestParam("definition") String definition){
	
    Term term = termService.rename(id,definition);
    return CarryDto.of(TermDto.of(term));
  }
  @RequestMapping(value = "/terms/retheme",method = RequestMethod.PUT)
  public CarryDto<TermDto> retheme(@RequestParam("theme") String theme){
	
    Term term = termService.retheme(root(),theme);
    return CarryDto.of(TermDto.of(term));
  }
  @RequestMapping(value = "/terms/{id:\\d+}/redirection",method = RequestMethod.PUT)
  public CarryDto<TermDto> redirection(@PathVariable Long id,@RequestParam("direction") String direction){
    Term term = termService.redirection(id,direction);
    return CarryDto.of(TermDto.of(term));
  }
  
  @RequestMapping(value = "/terms/{id:\\d+}/recost",method = RequestMethod.PUT)
  public CarryDto<TermDto> recost(@PathVariable Long id,@RequestParam("cost") Float cost){
    Term term = termService.recost(id,cost);
    return CarryDto.of(TermDto.of(term));
  }
  @RequestMapping(value = "/terms/{id:\\d+}/newdocument",method = RequestMethod.PUT)
  public CarryDto<TermDto> add_document(@PathVariable Long id){
	Document tmp = new Document();
	documentService.create(tmp);
    Term term = termService.setDocument(id,tmp.getId());
    return CarryDto.of(TermDto.of(term));
  }
  @RequestMapping(value = "/terms/search/draw",method = RequestMethod.GET)
  public TermGraphDto termsearch(@RequestParam(value = "center",required = false) Long centerId,
                                 @RequestParam(value = "depth",required = false) Integer depth){
    if(centerId==null) centerId = searchroot();
    if(centerId == null) throw BadRequestException.Root_Defect; 
    return TermGraphDto.of(termService.descendant(centerId,depth));
  }
  
  @RequestMapping(value = "/terms",method = RequestMethod.GET)
  public TermGraphDto descendant(@RequestParam(value = "center",required = false) Long centerId,
                                 @RequestParam(value = "depth",required = false) Integer depth){
    if(centerId==null) centerId = root();
    if(centerId == null) throw BadRequestException.Root_Defect; 
    return TermGraphDto.of(termService.descendant(centerId,depth));
  }
  
  @RequestMapping(value = "/terms/theme",method = RequestMethod.GET)
  public CarryDto<TermDto> getTheme(){
    return CarryDto.of(TermDto.of(termService.load(root())));
  }
  
  @RequestMapping(value = "/terms/{id:\\d+}/links",method = RequestMethod.GET)
  public ListDto<TermDto> links(@PathVariable Long id){
    return ListDto.of(termService.listLinked(id,null),TermDto::of);
  }

  @RequestMapping(value = "/terms/{id:\\d+}/parent",method = RequestMethod.GET)
  public CarryDto<TermDto> parent(@PathVariable Long id){
    return CarryDto.of(TermDto.of(termService.parent(id,root())));
  }

  @RequestMapping(value = "/terms/{id:\\d+}/children",method = RequestMethod.GET)
  public ListDto<TermDto> children(@PathVariable Long id){
    return ListDto.of(termService.listChildren(id,root()),TermDto::of);
  }
  
  @RequestMapping(value = "/terms/search",method = RequestMethod.GET)
  public ListDto<TermDto> searchByDefinition(@RequestParam("definition") String definition){
    return ListDto.of(termService.searchByDefinition(definition),TermDto::of);
  }
  
  @RequestMapping(value = "/terms/searchRoot",method = RequestMethod.GET)
  public ListDto<TermDto> searchRootByDefinition(@RequestParam("definition") String definition){
    return ListDto.of(termService.searchRootByDefinition(definition,file()),TermDto::of);
  }

  @RequestMapping(value = "/terms/searchrelate/draw",method = RequestMethod.GET)
  public TermGraphDto termsearchdef(@RequestParam(value = "center",required = false) Long centerId,
          @RequestParam(value = "depth",required = false) Integer depth){
    if(centerId==null) centerId = searchroot();
    if(centerId == null) throw BadRequestException.Root_Defect;
    return TermGraphDto.of(termService.descendantRelated(centerId,depth));
  }
  
}
